const compileUtil = {
	// 获取data中的对象值
	getValue(express, vm) {
		return express.split('.').reduce((data, currentVal) => {
			// console.log(currentVal);
			return data[currentVal]
		}, vm.$data)
	},
	setValue(express, vm, inputValue) {
		return express.split('.').reduce((data, currentVal) => {
			data[currentVal] = inputValue;
		}, vm.$data)
	},
	// 区分开{{}}--{{}}
	getContentValue(express, vm) {
		return express.replace(/\{\{(.+?)\}\}/g, (...args) => {
			return this.getValue(args[1], vm);
		})
	},
	// v-text
	text(node, express, vm) {
		let value;
		if(express.indexOf('{{') !== -1) {
			// {{msg}}
			value = express.replace(/\{\{(.+?)\}\}/g, (...args) => {
				// 绑定观察者
				new Watcher(vm, args[1], (newValue) => {
					this.updater.textUpdater(node, this.getContentValue(express, vm));
				})
				return this.getValue(args[1], vm);
			})
		} else {
			value = this.getValue(express, vm);
		}
		this.updater.textUpdater(node, value);
	},
	// v-html
	html(node, express, vm) {
		let value = this.getValue(express, vm);
		new Watcher(vm, express, (newValue) => {
			this.updater.htmlUpdater(node, newValue);
		});
		this.updater.htmlUpdater(node, value);
	},
	// v-model
	model(node, express, vm) {
		// 数据-视图
		const value = this.getValue(express, vm);
		new Watcher(vm, express, (newValue) => {
			this.updater.modelUpdater(node, newValue);
		});
		// 视图-数据-视图
		node.addEventListener('input', e => {
			this.setValue(express, vm, e.target.value);
		})
		this.updater.modelUpdater(node, value);
	},
	// v-on
	on(node, express, vm, event) {
		const f = vm.$options.methods && vm.$options.methods[express];
		node.addEventListener(event, f.bind(vm), false);
	},
	bind(node, express, vm, attribute) {
		const value = this.getValue(express, vm);
		this.updater.bindUpdater(node, attribute, value);
	},
	updater: {
		textUpdater(node, value) {
			node.textContent = value;
		},
		htmlUpdater(node, value) {
			node.innerHTML = value;
		},
		modelUpdater(node, value) {
			node.value = value;
		},
		bindUpdater(node, attribute, value) {
			node.setAttribute(attribute, value);
		}
	}
}

class Watcher {
	constructor(vm, express, callback) {
		this.vm = vm;
		this.express = express;
		this.callback = callback;
		// 保存旧值
	    this.oldValue = this.getOldValue();
	}
	getOldValue() {
		Dep.target = this;
		let old = compileUtil.getValue(this.express, this.vm);
		Dep.target = null;
		return old;
	}
	update() {
		const newValue = compileUtil.getValue(this.express, this.vm);
		if(newValue !== this.oldValue) {
			this.callback(newValue);
		}
	}
}

class Dep {
	// 收集watcher,通知watcher
	constructor() {
	    this.subs = [];
	}
	// 收集watcher
	addSub(watcher) {
		this.subs.push(watcher);
	}
	// 通知watcher更新
	notify() {
		console.log("观察者", this.subs);
		this.subs.forEach(watcher => {
			watcher.update()
		})
	}
}

class Observer {
	constructor(data) {
	    this.observer(data);
	}
	observer(data) {
		if(data && typeof data === 'object') {
			Object.keys(data).forEach(key => {
				this.defineReactive(data, key, data[key]);
			})
		}
	}
	defineReactive(data, key, value) {
		this.observer(value);
		const depend = new Dep();
		// 劫持
		Object.defineProperty(data, key, {
			enumerable: true,
			configurable: false,
			get() {
				// 数据初始化的时候添加订阅
				Dep.target && depend.addSub(Dep.target)
				return value;
			},
			set: (newValue) => {
				this.observer(newValue);
				if(newValue !== value) {
					value = newValue;
				}
				// 通知Dep变化
				depend.notify();
			}
		})
	}
}
class Compile {
	constructor(el, vm) {
		// 赋值/获取节点
		this.el = this.isElementNode(el) ? el : document.querySelector(el);
		this.vm = vm;
		// 获取子元素文档碎片
		const frag = this.fragment(this.el);
		// console.log(frag);
		// 编译模板
		this.compile(frag);

		// 追加子元素到根元素
		this.el.appendChild(frag);

	}
	compile(fragment) {
		const children = fragment.childNodes;
		[...children].forEach(child => {
			if (this.isElementNode(child)) {
				// 元素节点
				this.compileElement(child);
			} else {
				// 文本节点
				this.complieText(child);
			}

			if (child.childNodes && child.childNodes.length) {
				this.compile(child)
			}
		});
	}
	complieText(text) {
		const content = text.textContent;
		if(/\{\{(.+?)\}\}/.test(content)) {
			compileUtil['text'](text, content, this.vm);
		}
	}
	compileElement(node) {
		const attributes = node.attributes;
		[...attributes].forEach(attribute => {
			const {
				name,
				value
			} = attribute;
			if (this.isDire(name)) {
				const [, dirctive] = name.split('-');
				const [dirName, eventName] = dirctive.split(':');
				// 更新视图
				compileUtil[dirName](node, value, this.vm, eventName);
				// 删除指令
				node.removeAttribute('v-' + dirctive);
			} else if(this.isEventName(name)) {// 判断@符号
				let [, eventName] = name.split('@');
				compileUtil['on'](node, value, this.vm, eventName);
			} else if(this.isBindName(name)) {
				let [, attr] = name.split(':');
				compileUtil['bind'](node, value, this.vm, attr);
			}
		})
	}
	isBindName(name) {
		return name.startsWith(':')
	}
	isEventName(name) {
		return name.startsWith('@')
	}
	isDire(name) {
		return name.startsWith('v-')
	}
	fragment(el) {
		// 创建文档碎片
		const nodeFrag = document.createDocumentFragment();
		while (el.firstChild) {
			nodeFrag.appendChild(el.firstChild);
		}
		return nodeFrag;
	}
	isElementNode(node) {
		return node.nodeType === 1;
	}
}
class MyVue {
	constructor(options) {
		this.$el = options.el;
		this.$data = options.data;
		this.$options = options;
		if (this.$el) {
			// 观察者
			new Observer(this.$data);
			// 指令解析器
			new Compile(this.$el, this)
			// 代理
			this.proxyData(this.$data);
		}
	}
	proxyData(data) {
		for(let key in data) {
			Object.defineProperty(this, key, {
				get() {
					return data[key];
				},
				set(newValue) {
					data[key] = newValue;
				}
			}) 
		}
	}
}
